/**
 * @file userparam.c
 * @brief Implementa le funzioni per gestire una struttura UserParam.
 *
 * Vengono fornite delle funzioni di utilità per ricavare da una stringa la giusta
 * formattazione dei parametri e quindi una suddivisione in coppie {nomeparametro;valoreparametro}.
 *
 * @date Mar 22, 2012
 * @author Francesco Corvino
 */
#include "userparam.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

/**
 * @brief Funzione che restituisce la prima posizione dei caratteri forniti nella stringa passata.
 */
int UserParam_getFirstPos(char * str, const char * chars) {
	int i; char *ptr;
	for(i =0;i<strlen(chars);i++){
		if((ptr =strchr(str,chars[i]))!=NULL){
			return ptr - str;
		}
	}
	return strlen(str);
}

/**
 * @brief Inizializza una struttura UserParam assegnandone il nome e il valore.
 *
 * L'oggetto fornito deve essere già inizializzato, non vengono effettuate operazioni di allocazione per
 * l'attributo UserParam.
 *
 * @param p puntatore alla struttura UserParam da inizializzare.
 * @param namep nome da assegnare
 * @param valuep valore da assegnare al parametro
 */
void UserParam_init(UserParam* p,char *namep, char *valuep){
	int sizes = strlen(namep) + 1;
	if((p->name = malloc(sizes))!=NULL){
		strcpy(p->name,namep);
		p->name[sizes-1] = '\0';
	} else p->name = NULL;
	sizes = strlen(valuep) + 1;
	if((p->value = malloc(sizes))!=NULL){
		strcpy(p->value,valuep);
		p->value[sizes-1] = '\0';
	} else p->value = NULL;
}

/**
 * @brief effettua la liberazione della memoria allocata per un parametro.
 *
 * @param param puntatore alla struttura UserParam da liberare.
 */
void UserParam_destroy(const void * param){
	UserParam* p = (UserParam*) param;
	free(p->name); free(p->value);
}

/**
 * @brief Effettua la copia di una stringa.
 *
 * @param src puntatore alla stringa da copiare.
 * @param cpysize intero che indica il numero di byte da copiare.
 *
 * @return il puntatore alla stringa copiata, NULL in caso di errore.
 */
char * _UserParam_cpy(char *src,int cpysize){
	char *retCpy;
	// alloca la memoria, è necessario un byte in più per assegnare il carattere \0
	if((retCpy = malloc(cpysize + 1))==NULL) return NULL;
	// copia e termina con null la stringa
	memcpy(retCpy,src, cpysize);
	retCpy[cpysize] = '\0';
	return retCpy;
}

/**
 * @brief ricerca il primo parametro all'interno di una stringa.
 *
 * @param p puntatore alla struttura dati UserParam da modificare con i nuovi valori individuati.
 * @param line puntatore alla stringa da parserizzare alla ricerca del parametro.
 * @param divName carattere che specifica dove viene suddiviso il nome dal valore.
 * @param divValue carattere che specifica la terminazione di un valore.
 *
 * @return numero di byte letti per il parametro.
 */
int UserParam_find(UserParam *p, char * line, char divName, char divValue){
	char *tmpPtr, *endline;
	int lastPos;

	//recupera il nome individuando il carattere separatore
	if((tmpPtr = strchr(line,divName))==NULL) return 0;
	p->name = _UserParam_cpy(line,tmpPtr-line);

	//recupera il valore ed effettua il calcoli di fine stringa
	if((endline = strchr(tmpPtr,divValue))==NULL)
		endline = line + strlen(line); // carattere non trovato posizione a fine stringa
	lastPos = endline-tmpPtr -1; // calcolo la dimensione
	p->value = _UserParam_cpy(tmpPtr + 1,lastPos);
	return endline - line + 1;
}

/**
 * @brief analizza un'intera linea aggiungendo i parametri all'array fornito.
 *
 * @see UserParam_find funzione utilizzata per individuare ogni singolo parametro.
 */
void UserParam_fillArr(DynArray * arr, char *line, char divName, char divValue){
	// controlla che sia un array adatto per aggiungere parametri
	if(arr->sizeSingleElem != sizeof(UserParam)) return;
	arr->destroy = UserParam_destroy;
	// avvia le operazioni di parserizzazione dei parametri
	UserParam p; char *first = line; char *end = first + strlen(line);
	while(1){
		int res = UserParam_find(&p,first,divName,divValue);
		if(res!=0) DynArray_add(arr,&p);
		if((res==0) ||(res >= end-first) ) break;
		first += res;
	}
}

/**
 * @brief funzione utilizzata per confrontare due parametri attraverso il nome.
 *
 * @param a puntatore rappresentante il primo parametro.
 * @param b puntatore rappresentante il secondo parametro.
 */
int UserParam_cmp(const void *a, const void *b){
	UserParam *A, *B;
	if((a==NULL)&&(b==NULL)) return 0;
	if(a!=NULL) A = (UserParam*) a; else return -1;
	if(b!=NULL) B = (UserParam*) b; else return 1;
	return strcmp(A->name, B->name);
}

/**
 * @brief Restituisce un parametro da un'array di parametri.
 *
 * @param arr array da controllare.
 * @param name nome del parametro da cercare.
 *
 * @return NULL se il parametro non è stato individuato, altrimenti il parametro individuato.
 */
UserParam* UserParam_getFromDynArray(DynArray * arr, char*name){
	// crea l'elemento di ricerca findElem
	UserParam findElem;
	UserParam_init(&findElem,name, "");
	// effettua la ricerca
	void* tmp =DynArray_get(arr,&findElem);
	// libera la memoria occupata
	UserParam_destroy(&findElem);
	// restituisce il risultato
	if(tmp==NULL) return NULL;
	return (UserParam*) tmp;
}
